home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / System 7.0 Samples / AEObject-Edition1.0.2 Sample / Subscribe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-09  |  57.9 KB  |  1,232 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. *
  3. *  Apple Developer Technical Support
  4. *
  5. *  Edition subscribing routines
  6. *
  7. *  Program:    AEObject-Edition Sample
  8. *  File:       Subscribe.c -   C Source
  9. *
  10. *  by:         C.K. Haun <TR>
  11. *
  12. *  Copyright © 1990-1992 Apple Computer, Inc.
  13. *  All rights reserved.
  14. *
  15. *------------------------------------------------------------------------------
  16. * This file handles the Subscribe section of the program.  It also handles some of 
  17. * the common use routines, like the section options dialog.
  18. *----------------------------------------------------------------------------*/
  19.  
  20. #define __SUBSCRIBE__
  21.  
  22. #pragma segment Subscribe
  23.  
  24. #include "Sampdefines.h"
  25. /* this point tells EM to center our expanded box, if we're using that feature */
  26. Point expPoint = 
  27. {
  28.     -1, -1
  29. };
  30.  
  31.  
  32.  
  33.  
  34. /* DoSubscribe presents the user with the Subscriber dialog, and allows the user to */
  35. /* subscribe to a PICT type edition, anywhere, anytime.  It also stores the */
  36. /* section handle returned in the window data structure for the current window */
  37. /* You can only subscribe to TEXT if you have a text box open in the current window.  */
  38. /* Optionally, of course, you can put in your own conversion of the TEXT to a PICT and */
  39. /* subscribe to that as such, same as you would with clipboard types. */
  40.  
  41. void DoSubscribe(void)
  42. {
  43.     OSErr myErr;
  44.     SectionHandle secHandle;
  45.     windowCHandle shortName;
  46.     NewSubscriberReply GetSub;
  47.     shortName = (windowCHandle)GetWRefCon(FrontWindow());       /* get our struct */
  48.     GetSub.formatsMask = kPICTformatMask;                   /* tell the dialog we only want PICT type editions */
  49.     if ((*shortName)->boxHandle != nil)                     /* is there a text box already? */
  50.         GetSub.formatsMask += kTEXTformatMask;
  51.     /* GetLastEditionContainerUsed gives you either the last edition container used  */
  52.     /* (either pub or sub, since they are the same to the Edition Manager) or if there */
  53.     /* was not a previous container, it fills it with a default container. */
  54.     GetLastEditionContainerUsed(&GetSub.container);
  55.     /* Now ask the user to select an edition to subscribe to */
  56.     if (!gExpanded)
  57.         myErr = NewSubscriberDialog(&GetSub);
  58.     else
  59.         myErr = NewSubscriberExpDialog(&GetSub, expPoint, kExpandedDITL, (ExpDlgHookProcPtr)ExpOptHook,
  60.                                        (ExpModalFilterProcPtr)ExpOptFilter, nil);
  61.     if (myErr != noErr) {                                   /* bail on fail */
  62.         ShowMe("\pNewSubscriberDialog", myErr, __LINE__);
  63.         return;
  64.     }
  65.     if (GetSub.canceled)                                    /* did they cancel the dialog? */
  66.         return;
  67.     HLock((Handle)shortName);
  68.     /* Now create a new section record for the container the user picked.  In other words, the */
  69.     /* Edition manager keeps track of things by the container, and will give you a section */
  70.     /* record that refers to it for you to keep track with.  */
  71.     /* ••• NOTE: Whenever the Edition Manager gives you memory (like the section handle) */
  72.     /* it came out of your heap, and YOU are responsible for disposing of it when you are */
  73.     /* completely done (and have UnRegistered) the section.  If you're not careful about this */
  74.     /* then you'll get creeping memory loss.  */
  75.     /* Now see if the window has ever been saved.  If so, we can store a reference to */
  76.     /* the file in the section */
  77.     if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) {
  78.         myErr = NewSection(&GetSub.container, nil, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, &secHandle);
  79.     } else {
  80.         /* if the file has been saved once, then we can store a reference to the 'parent' file */
  81.         /* in the edition */
  82.         FSSpec tempSpec;
  83.         Boolean myWasChanged;
  84.         myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged);
  85.         myErr = NewSection(&GetSub.container, &tempSpec, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic,
  86.                            &secHandle);
  87.     }
  88.     if (myErr != noErr) {
  89.         ShowMe("\pNewSection", myErr, __LINE__);
  90.         return;
  91.     }
  92.     /* section successfully gotten.  Add it to the current window section list please */
  93.     /* Handle this in whatever way is appropriate for your application, of course.  */
  94.     /* The main point to remember is that you _must_ keep track of the section handles, */
  95.     /* they are your method (only method) for comunication between your application */
  96.     /* and the Edition Manager, you will be passing sections to the EM, and it will be */
  97.     /* passing them back to you. */
  98.     gSectionID++;                                           /* increment our unique ID */
  99.     StoreSubscriber(shortName, secHandle, nil, nil);
  100.     HUnlock((Handle)shortName);
  101. }
  102.  
  103. /* end DoSubscribe */
  104. /* DoOptions handles the SectionOptions menu selection.  The handle passed */
  105. /* (inSection) is a subscriber OR publisher section, the Edition Manager will figure */
  106. /* out what dialog to display by looking at the section record */
  107. /* ••• BE CAREFUL with the section  handle you pass to the options dialog (or anywhere, for that matter) */
  108. /* A section that has not been registered, or a section containing a bad alias handle, will */
  109. /* cause the options dialog to blow up in unusual and fun ways */
  110. /* This call also includes the expanded section options dialog box with one */
  111. /* extra item, to show how it's used. */
  112. void DoOptions(SectionHandle inSection)
  113. {
  114.     OSErr myErr;
  115.     SectionOptionsReply oreply;
  116.     Boolean subExpansion;
  117.     
  118.     oreply.sectionH = inSection;                            /* put the section passed in the reply record */
  119.     if ((*inSection)->kind == stSubscriber)
  120.         subExpansion = true;
  121.     else
  122.         subExpansion = false;
  123.     myErr = IsRegisteredSection(inSection);
  124.     if (myErr != noErr) {
  125.         ShowMe("\p Bad Section ", myErr, __LINE__);
  126.         return;
  127.     }
  128.     if (subExpansion) {
  129.         myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedSubDITL, (ExpDlgHookProcPtr)SubExpOptHook,
  130.                                         (ExpModalFilterProcPtr)SubExpOptFilter, nil);
  131.     } else {
  132.         if (!gExpanded)
  133.             myErr = SectionOptionsDialog(&oreply);          /* run the dialog */
  134.         else
  135.             myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedDITL, (ExpDlgHookProcPtr)ExpOptHook,
  136.                                             (ExpModalFilterProcPtr)ExpOptFilter, nil);
  137.     }
  138.     if (myErr != noErr) {
  139.         ShowMe("\pSection Options", myErr, __LINE__);
  140.         return;
  141.     }
  142.     if (oreply.canceled)                                    /* if user canceled */
  143.         return;
  144.     if (oreply.action == sectionReadMsgID) {
  145.         /* if the user clicked 'Get Edition Now' you'll call your section read routine, the same */
  146.         /* one that gets called on a sect read AppleEvent */
  147.         MyReadSection(inSection);
  148.     } else {
  149.         if (oreply.action == sectionWriteMsgID) {
  150.             /* if the user clicked 'Send Edition Now' you'll call your section write routine, the same */
  151.             /* one that gets called on a sect writ AppleEvent */
  152.             MyUpdateEdition(inSection);
  153.         } else {
  154.             if (oreply.action == 'goto') {  /* why isn't there a constant fo this? */
  155.                 /* this is the sect scrl (section scroll) event from the dialog */
  156.                 /* the dialog has already taken the action for you, that's it's job */
  157.             } else {
  158.                 if (oreply.action == emCancelSectionDialogRefCon) {
  159.                     /* This is for canceling a section, either pub or sub, you have to make the */
  160.                     /* choice based on what the section is */
  161.                     SectionType tempST;
  162.                     HLock((Handle)inSection);
  163.                     tempST = (*inSection)->kind;            /* what kinda thing is this? */
  164.                     HUnlock((Handle)inSection);
  165.                     
  166.                     MyCancelSection(inSection, FindSection(inSection));
  167.                 }
  168.             }
  169.         }
  170.     }
  171. }
  172.  
  173. /* end DoOptions */
  174.  
  175. /* AEReadSectionHandler is the handler I installed in the AppleEvent manager list for */
  176. /* AppleEvents of the type 'sect' 'read'.  What this means is that whenever I get a */
  177. /* high level event of the type 'sect' 'read' this routine will be dispatched to when I */
  178. /* call AEProcessAppleEvent (in AppleEventM.c).   This is where the actual section data */
  179. /* gets read in, when the Edition Manager tells you the edition is ready to read */
  180. pascal OSErr AEReadSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  181. {
  182. #pragma unused (reply,refIn)
  183.     SectionHandle theSection;
  184.     OSErr myErr;
  185.     
  186.     myErr = GetSectionHandleFromEvent(messagein, &theSection);      /* in AppleEventM.c */
  187.     if (myErr) {
  188.         ShowMe("\pGetSectionHandleFromEvent", myErr, __LINE__);
  189.         return(myErr);
  190.     }
  191.     /* This next step is very important.  Unexpected things can happen to you, */
  192.     /* a section could disappear between the time an event gets posted and when it */
  193.     /* finally gets to your application (particularly since AppleEvents are the lowest in */
  194.     /* the event hierarchy), the section may have been canceled, deleted, disk off-line, or */
  195.     /* whatever.  You must make a current check with the EM to see if the section that */
  196.     /* you are supposed to read. */
  197.     myErr = IsRegisteredSection((SectionHandle)theSection);
  198.     if (myErr) {
  199.         ShowMe("\pRead IsRegisteredSection", myErr, __LINE__);
  200.         return(myErr);
  201.     }
  202.     /* It is a valid section.  Jump to my routine that opens and reads it */
  203.     MyReadSection(theSection);
  204. }
  205.  
  206. /* end AEReadSectionHandler */
  207.  
  208. /* MyReadSection opens and reads the edition data into my window data structure. */
  209. OSErr MyReadSection(SectionHandle theSection)
  210. {
  211.     OSErr myErr;
  212.     EditionRefNum sRefNum=0;
  213.     Size dataSize;
  214.     Boolean existed = false;                                /* for setting the display rect */
  215.     /* open the edition and get a ref number */
  216.     SpinCursor();
  217.     myErr = OpenEdition(theSection, &sRefNum);
  218.     if (myErr) {
  219.         if(sRefNum)CloseEdition(sRefNum,true);
  220.         ShowMe("\pOpenEdition", myErr, __LINE__);
  221.         return(myErr);
  222.         
  223.     }
  224.     /* Here we are double-checking the edition.  I'm first checking for PICT data, */
  225.     /* and as a handy side effect, it gives us the size of the data (returned in my */
  226.     /* variable dataSize) for us to use when we read it later */
  227.     
  228.     
  229.     if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize))) {
  230.         /* It does have a pict, read it in */
  231.         register  jj;                                    /* loop vars for window search */
  232.         long subIDtofind;
  233.         
  234.         /*  There is already a handle allocated for this picture in the window structure. 
  235.         *   Find it, resize it (since the edition size could have changed) and fill it.
  236.         *       Keep in mind that the section read may happen for a window which is not 
  237.         *       frontmost, so we need to search all the windows to find the ID */
  238.         WindowPtr tempPort;
  239.         Boolean secFound = false;
  240.         SectionHandle *tempPtr;
  241.         SectionRecord *tempRecord;
  242.         Handle tempHandle;
  243.         WindowPtr tempNextWindow;
  244.         Rect *tempRect;
  245.         Rect holdRect;
  246.         SpinCursor();
  247.         HLock((Handle)theSection);
  248.         subIDtofind = (*theSection)->sectionID;             /* what ID are we reading?  */
  249.         /* check to see if this is the clipboard's section.  If so, let the clipboard */
  250.         /* handle it */
  251.         if ((subIDtofind == (*gClipSection)->sectionID) && (gClipSection != nil)){
  252.             return(ReadClipSection(dataSize, sRefNum));
  253.             }
  254.         GetPort(&tempPort);                                 /* save the current port */
  255.         /* search window list now */
  256.         tempNextWindow = mWindList;                         /* start at the beginning of the chain */
  257.         while (tempNextWindow) {
  258.             SpinCursor();
  259.             if (((WindowPeek)tempNextWindow)->windowKind == kDocumentWindow) {
  260.                 windowCHandle tempWC;
  261.                 /* do housekeeping to get to the section handle list */
  262.                 tempWC = (windowCHandle)GetWRefCon(tempNextWindow);
  263.                 HLock((Handle)tempWC);
  264.                 tempHandle = (*tempWC)->subs;               /* handle containing SectionHandles */
  265.                 HLock(tempHandle);
  266.                 tempPtr = (SectionHandle *)*tempHandle;
  267.                 /* Loop through all our sections until we find this edition */
  268.                 for (jj = 0; jj < (*tempWC)->numSubs; jj++) {
  269.                     Handle *newTemp;
  270.                     SpinCursor();
  271.                     HLock((Handle)*tempPtr);
  272.                     tempRecord = *(*tempPtr);
  273.                     if (tempRecord->sectionID == subIDtofind) {
  274.                         /* found the section belonging to this read. */
  275.                         /* can't break, since it is conceiveable that the user has more that one subscription in this document */
  276.                         SetPort(tempNextWindow);            /* set the port to the window we found the section in */
  277.                         HLock((*tempWC)->subDataHandle);
  278.                         newTemp = (Handle *)*((*tempWC)->subDataHandle);
  279.                         newTemp += jj;
  280.                         /* if the dataSize returned was -1 then the size was unknown when opened.  */
  281.                         /* in this case, this should only happen with our special opener.  */
  282.                         /* So, if it is -1, then we'll have to handle the read */
  283.                         /* in a series of steps to get the right amount of data */
  284.                         /* For now, I'll leave that out until I put in a custom */
  285.                         /* opener. Watch this space */
  286.                         if (dataSize != -1) {
  287.                             HUnlock(*newTemp);
  288.                             MySetHandleSize(*newTemp, dataSize);
  289.                             HLock(*newTemp);
  290.                         }
  291.                         SpinCursor();
  292.                         /* read the pict in */
  293.                         myErr = MyReadEditionData(**newTemp, kGenericPICTWord, sRefNum, &dataSize);
  294.                         /* ••••• NOTE: After much discussion with our Human Interface folks and the */
  295.                         /* Edition Manager engineer, we've decided that the interface guidelines */
  296.                         /* for editions will say that reading a subscription does _not_ dirty */
  297.                         /* a document.  A lot of soul-searching went on to make this decision, and */
  298.                         /* we decided this way primarily to keep the user from getting confused.  */
  299.                         /* Editions should be as transparent and automatic as possible, and reminding */
  300.                         /* the user that an edition is a 'special' thing that they have to do */
  301.                         /* unusual things with to make work right will remove some of that */
  302.                         /* automation.  Of course, the 'cached' version of the subscription that */
  303.                         /* you save with the document should be updated when the subscription changes */
  304.                         /* So, the following line was commented out. */
  305.                         /* (*tempWC)->windowDirty = true;  */
  306.                         /* mark window dirty on every read */
  307.                         holdRect = (*(PicHandle)(*newTemp))->picFrame;
  308.                         HUnlock(*newTemp);
  309.                         /* put the picture in the corner, if it didn't exist.  If it did, adjust the rect as
  310.                         *   required */
  311.                         HLock((*tempWC)->subRects);
  312.                         newTemp = (Handle *)*((*tempWC)->subRects);
  313.                         newTemp += jj;
  314.                         /* if the handle is the size of a rect, I've seen this edition before */
  315.                         if (GetHandleSize(*newTemp) == sizeof(Rect)) {
  316.                             existed = true;                 /* it's already been made */
  317.                         } else {
  318.                             HUnlock(*newTemp);
  319.                             MySetHandleSize(*newTemp, sizeof(Rect));        /* new subscription */
  320.                         }
  321.                         HLock(*newTemp);
  322.                         tempRect = (Rect *)*(*newTemp);
  323.                         if (!existed) {
  324.                             tempRect->top = tempRect->left = 0;
  325.                             tempRect->bottom = holdRect.bottom - holdRect.top;
  326.                             tempRect->right = holdRect.right - holdRect.left;
  327.                         } else {
  328.                             InvalRect(tempRect);            /* refresh the old image if the thing was resized */
  329.                             /*          tempRect->bottom = tempRect->top + (holdRect.bottom - holdRect.top);
  330.                             tempRect->right = tempRect->left + (holdRect.right - holdRect.left);
  331.                             */
  332.                         }
  333.                         InvalRect(tempRect);
  334.                         HUnlock(*newTemp);
  335.                         HUnlock((Handle)*tempPtr);
  336.                         
  337.                     } else {
  338.                         HUnlock((Handle)*tempPtr);
  339.                         tempPtr += 1;
  340.                     }
  341.                 }                                           /* section handle loop jj */
  342.  
  343.                 HUnlock(tempHandle);
  344.                 HUnlock((Handle)tempWC);
  345.                 /* ••• NOTE: You'll notice that there is no break or exit from this section searching loop */
  346.                 /* Why?  Because there may be many subscribers to the same edition.  The user may */
  347.                 /* have multiple subscribtions in the same window, or in any of his or her windows. */
  348.                 /* Don't assume that there is only one subscriber (unless you require it, which may be */
  349.                 /* reasonable for a single document but _not_ for a multi-document application), run */
  350.                 /* your whole list each time to be certain everything gets refreshed */
  351.             }                                               /* if document */
  352.             SpinCursor();
  353.             tempNextWindow = (WindowPtr)((WindowPeek)tempNextWindow)->nextWindow;
  354.         }                                                   /* window loop qq */
  355.         SetPort(tempPort);                                  /* reset the port to what it was when we entered */
  356.     } else {
  357.         if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericTEXTWord, &dataSize))) {
  358.             WindowPtr theWindow;
  359.             windowCHandle tempWC;
  360.             TEHandle tempTEH;
  361.             mySectionDataHandle theTES;
  362.             long tempStart, tempEnd;
  363.             SpinCursor();
  364.             /* it's a text subscription.  That means we search in the text path, and also need */
  365.             /* to update the TEHandle for the window this goes with */
  366.             theWindow = FindSection(theSection);
  367.             theTES = TextSectionFromSecHandle(theSection);
  368.             HLock((Handle)theTES);
  369.             tempWC = (windowCHandle)GetWRefCon(theWindow);
  370.             tempTEH = (*tempWC)->boxHandle;
  371.             /* save the current TE selection range so that the user is returned to the */
  372.             /* place he or she was before we did the reading, so the text doesn't jump */
  373.             /* around all loony on them */
  374.             tempStart = (*tempTEH)->selStart;
  375.             tempEnd = (*tempTEH)->selEnd;
  376.             
  377.             /* first thing we need to do is remove whatever the current sub data in our */
  378.             /* TE Record is.  if there is any, o'course */
  379.             if ((*theTES)->startChar != (*theTES)->endChar) {
  380.                 TESetSelect((*theTES)->startChar, (*theTES)->endChar, (TEHandle)tempTEH);
  381.                 TEDelete(tempTEH);
  382.             }
  383.             SetHandleSize((*theTES)->additionalData, dataSize);
  384.             HLock((*theTES)->additionalData);
  385.             MyReadEditionData(*(*theTES)->additionalData, kGenericTEXTWord, sRefNum, &dataSize);
  386.             SpinCursor();
  387.             /* that gives us the text.  Now we need to adjust our endpoint */
  388.             (*theTES)->endChar = ((*theTES)->startChar) + dataSize;
  389.             /* set insertion point to where we want to be */
  390.             TESetSelect((*theTES)->startChar, (*theTES)->startChar, tempTEH);
  391.             TEInsert(*(*theTES)->additionalData, dataSize, tempTEH);
  392.             HUnlock((*theTES)->additionalData);
  393.             HUnlock((Handle)theTES);
  394.             /* reset insertion point to what it once was */
  395.             TESetSelect(tempStart, tempEnd, tempTEH);
  396.         }
  397.     }
  398. }
  399.  
  400. /* end MyReadSection */
  401.  
  402. OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch)
  403. {
  404.     OSErr myErr;
  405.     if (myErr = ReadEdition(readRef, typeToGet, readinPtr, howMuch))
  406.         CloseEdition(readRef, false);
  407.     else
  408.         CloseEdition(readRef, true);
  409.         if(myErr)ShowMe("\p reading error",myErr,0);
  410.     return(myErr);
  411. }
  412.  
  413. /*  HandleSectionSave handles saving and closing of subscribers for */
  414. /*       a document.  The Boolean flags tell this function wheither to write */
  415. /*       ouut the data [on save or save/close] and weither to UnRegister */
  416. /*       the sections [on close]. */
  417. /*       The resource fork is open on entry. */
  418. /* theWind is locked on entry */
  419. void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec)
  420. {
  421.     SectionHandle *theSections;
  422.     Handle *newTemp;
  423.     SectionRecord secRec;
  424.     Handle tempHandle;
  425.     Rect *tempRectPtr;
  426.     register qq;
  427.     OSErr myErr;
  428.     if ((*theWind)->numSubs) {
  429.         Handle *tempPictPtr;
  430.         HLock((*theWind)->subs);
  431.         theSections = (SectionHandle *)*(*theWind)->subs;
  432.         /* and display rectangles */
  433.         HLock((*theWind)->subRects);
  434.         HLock((*theWind)->subDataHandle);
  435.         newTemp = (Handle *)*((*theWind)->subRects);
  436.         tempPictPtr = (Handle *)*((*theWind)->subDataHandle);
  437.         /* loop through the sections */
  438.         for (qq = 0; qq < (*theWind)->numSubs; qq++) {
  439.             SpinCursor();
  440.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  441.             myErr = AssociateSection(*theSections, theSpec);
  442.             if (myErr)
  443.                 ShowMe("\p Assocate", myErr, __LINE__);
  444.             
  445.             
  446.             
  447.             /* write the section handle out... */
  448.             if (writeEm) {
  449.                 tempHandle = (Handle)*theSections;
  450.                 HandToHand(&tempHandle);
  451.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  452.                 secRec = *(*(*theSections));                /* just for easier display below */
  453.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  454.                 /* now do the same with the alias record please */
  455.                 tempHandle = (Handle)secRec.alias;
  456.                 HandToHand(&tempHandle);
  457.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  458.                 HUnlock((Handle)*theSections);
  459.                 /* save off the display rect for this sub */
  460.                 tempHandle = *newTemp;
  461.                 HandToHand(&tempHandle);
  462.                 AddResource(tempHandle, kRECTType, secRec.sectionID, "");
  463.                 /* and save out the picture data, so we don't need to immediatly do a */
  464.                 /* section read when the file is opened */
  465.                 tempHandle = *tempPictPtr;
  466.                 HandToHand(&tempHandle);
  467.                 AddResource(tempHandle, kGenericPICTWord, secRec.sectionID, "");
  468.             }                                               /* writeEm if */
  469.             
  470.             if (dereg) {
  471.                 UnRegisterSection(*theSections);
  472.                 /* and dispose of the alias handle */
  473.                 DisposHandle((Handle)*(*(*theSections))->alias);
  474.                 /* and the section handle */
  475.                 DisposHandle((Handle)*theSections);
  476.                 /* and the rectangle handle */
  477.                 DisposHandle((Handle)*newTemp);
  478.                 /* picture handle disposed in closewindow */
  479.             }
  480.             theSections += 1;                               /* go to next section handle please */
  481.             newTemp += 1;                                   /* and next rectangle */
  482.         }
  483.         HUnlock((*theWind)->subRects);
  484.         HUnlock((*theWind)->subs);
  485.     }                                                       /* end subscriber save section */
  486.     /* now do the same thing for our publishers please */
  487.     /* Of course, here you'll also write the data if pumAutomatic is set */
  488.     
  489.     if ((*theWind)->numPubs) {
  490.         SpinCursor();
  491.         HLock((*theWind)->pubs);
  492.         theSections = (SectionHandle *)*(*theWind)->pubs;
  493.         /* and display rectangles */
  494.         HLock((*theWind)->pubRects);
  495.         tempRectPtr = (Rect *)*((*theWind)->pubRects);
  496.         
  497.         /* loop through the sections */
  498.         for (qq = 0; qq < (*theWind)->numPubs; qq++) {
  499.             SpinCursor();
  500.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  501.             AssociateSection(*theSections, theSpec);
  502.             /* write the section handle out... */
  503.             if (writeEm) {
  504.                 tempHandle = (Handle)*theSections;
  505.                 HandToHand(&tempHandle);
  506.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  507.                 secRec = *(*(*theSections));                /* just for easier display below */
  508.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  509.                 SpinCursor();
  510.                 /* now do the same with the alias record please */
  511.                 tempHandle = (Handle)secRec.alias;
  512.                 HandToHand(&tempHandle);
  513.                 
  514.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  515.                 SpinCursor();                
  516.                 HUnlock((Handle)*theSections);
  517.                 /* save off the display rect for this pub */
  518.                 
  519.                 tempHandle = NewHandle(sizeof(Rect));
  520.                 PtrToHand((Ptr)tempRectPtr, &tempHandle, sizeof(Rect));
  521.                 HandToHand(&tempHandle);
  522.                 AddResource(tempHandle, kRECTType, secRec.sectionID, "");
  523.                 SpinCursor();                
  524.                 if (secRec.mode == pumOnSave) {
  525.                     MyUpdateEdition(*theSections);
  526.                     /* and indicate that this was saved with a document */
  527.                     (*(*theSections))->refCon |= kSavedOnce;        /* OR in our saved flag with type */
  528.                 }
  529.             }                                               /* writeEm if for pubs */
  530.             
  531.             if (dereg) {
  532.                 UnRegisterSection(*theSections);
  533.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  534.                 /* then we'll delete it.  */
  535.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved) {
  536.                     OSErr myErr;
  537.                     FSSpec deleteSpec;
  538.                     Boolean myWasChanged;
  539.                     ResolveAlias(nil, ((*(*theSections))->alias), &deleteSpec, &myWasChanged);
  540.                     SpinCursor();                    
  541.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  542.                         ShowMe("\pDelete Editon", myErr, __LINE__);
  543.                     }
  544.                 }
  545.                 
  546.                 /* and dispose of the alias handle */
  547.                 DisposHandle((Handle)*(*(*theSections))->alias);
  548.                 /* and the section handle */
  549.                 DisposHandle((Handle)*theSections);
  550.                 
  551.             }
  552.             theSections += 1;                               /* go to next section handle please */
  553.             tempRectPtr += 1;                               /* and next rectangle */
  554.         }
  555.         HUnlock((*theWind)->pubRects);
  556.         HUnlock((*theWind)->pubs);
  557.     }
  558.     /* now save off any text sections in this document */
  559.     if ((*theWind)->textSections) {
  560.         mySectionDataHandle tempTS = (*theWind)->textSections;
  561.         do {
  562.             SpinCursor();
  563.             tempHandle = (Handle)(*tempTS)->theSection;
  564.             /* make sure the text is the latest */
  565.             RePackText(tempTS, (*theWind)->boxHandle);
  566.             AssociateSection((SectionHandle)tempHandle, theSpec);
  567.             
  568.             if (writeEm) {
  569.                 HandToHand(&tempHandle);
  570.                 myErr = MemError();
  571.                 if (myErr)
  572.                     ShowMe("\p memerr", myErr, __LINE__);
  573.                 HLock(tempHandle);                          /* lock down the original section so we can work with it */
  574.                 secRec = *(*(SectionHandle)tempHandle);     /* just for easier display below */
  575.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  576.                 SpinCursor();
  577.                 /* save the alias */
  578.                 tempHandle = (Handle)secRec.alias;
  579.                 HandToHand(&tempHandle);
  580.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  581.                 SpinCursor();
  582.                 /* now save a copy of my whole text record */
  583.                 
  584.                 tempHandle = (Handle)tempTS;
  585.                 HandToHand(&tempHandle);
  586.                 /* use the same ID number as the section, make things easy */
  587.                 /* zap any forward link in this, so StoreSection doesn't get */
  588.                 /* confused when the section is read back in */
  589.                 (*(mySectionDataHandle)tempHandle)->nextSection = nil;
  590.                 (*(mySectionDataHandle)tempHandle)->additionalData = nil;
  591.                 (*(mySectionDataHandle)tempHandle)->theSection = nil;
  592.                 AddResource(tempHandle, rMyTextRecordType, secRec.sectionID, "");
  593.                 
  594.                 /* and finally, the associated text */
  595.                 tempHandle = (*tempTS)->additionalData;
  596.                 HandToHand(&tempHandle);
  597.                 AddResource(tempHandle, rMyTextBlock, secRec.sectionID, "");
  598.                 SpinCursor();
  599.                 if (secRec.kind == stPublisher && secRec.mode == pumOnSave) {
  600.                     MyUpdateEdition((*tempTS)->theSection);
  601.                     /* and indicate that this was saved with a document */
  602.                     (*(*tempTS)->theSection)->refCon |= kSavedOnce;     /* OR in our saved flag with type */
  603.                 }
  604.             }                                               /* text writeem if */
  605.             
  606.             if (dereg) {
  607.                 UnRegisterSection((SectionHandle)tempHandle);
  608.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  609.                 /* then we'll delete it.  */
  610.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved && (*(*theSections))->kind == stPublisher) {
  611.                     OSErr myErr;
  612.                     FSSpec deleteSpec;
  613.                     Boolean myWasChanged;
  614.                     ResolveAlias(nil, (*(SectionHandle)tempHandle)->alias, &deleteSpec, &myWasChanged);
  615.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  616.                         ShowMe("\pSection Save Delete Editon", myErr, __LINE__);
  617.                     }
  618.                 }
  619.                 
  620.                 /* and dispose of the alias handle */
  621.                 DisposHandle((Handle)(*(SectionHandle)tempHandle)->alias);
  622.                 /* and the section handle */
  623.                 DisposHandle((Handle)tempHandle);
  624.                 
  625.             }
  626.             tempTS = (*tempTS)->nextSection;
  627.         }
  628.                 while (tempTS);
  629.         
  630.     }
  631. }
  632.  
  633. /* MyCancelSection cancels this section.  It removes  */
  634. /*  the section info from our window structure, and also de-registers the */
  635. /* section with (from) the Edition Manager.  If it's a publisher, it also  */
  636. /* deletes the edition file  */
  637.  
  638. void MyCancelSection(SectionHandle inSection, WindowPtr theWindow)
  639. {
  640.     OSErr myErr;
  641.     windowCHandle shortName;
  642.     SectionHandle *tempPtr;
  643.     Rect *tempRectPtr;
  644.     register qq;
  645.     FSSpec deleteSpec;
  646.     Boolean myWasChanged;
  647.     shortName = (windowCHandle)GetWRefCon(theWindow);
  648.     HLock((Handle)shortName);
  649.     
  650.     /* first thing to do is deregister the thing */
  651.     UnRegisterSection(inSection);
  652.     if ((*inSection)->kind == stPublisher) {                /* only delete publishers */
  653.         ResolveAlias(nil, ((*inSection)->alias), &deleteSpec, &myWasChanged);
  654.         if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  655.             ShowMe("\pCancel Delete Editon", myErr, __LINE__);
  656.         }
  657.     }
  658.     /* get rid of the alias handle for it */
  659.     DisposHandle((Handle)(*inSection)->alias);
  660.     if ((*inSection)->kind == stPublisher) {
  661.         HLock((*shortName)->pubs);                          /* lock down my list of section handles */
  662.         tempPtr = (SectionHandle *)*(*shortName)->pubs;
  663.         for (qq = 0; qq < (*shortName)->numPubs; qq++) {
  664.             HLock((Handle)*tempPtr);
  665.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  666.                 DisposHandle((Handle)inSection);
  667.                 DisposeHandle((Handle)(*(*tempPtr))->alias);
  668.                 DisposHandle((Handle)*tempPtr);
  669.                 HLock((*shortName)->pubRects);
  670.                 tempRectPtr = (Rect *)*((*shortName)->pubRects);
  671.                 tempRectPtr += qq;
  672.                 if (qq != (*shortName)->numPubs) {
  673.                     register ii;                            /* need to move information down */
  674.                     for (ii = qq; ii < ((*shortName)->numPubs) - 1; ii++) {
  675.                         *tempPtr = *(tempPtr + 1);
  676.                         *tempRectPtr = *(tempRectPtr + 1);
  677.                         tempPtr += 1;
  678.                         tempRectPtr += 1;
  679.                     }
  680.                 }
  681.                 (*shortName)->numPubs--;
  682.                 HUnlock((*shortName)->pubs);
  683.                 MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) - sizeof(Handle));
  684.                 HUnlock((*shortName)->pubRects);
  685.                 MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) - sizeof(Rect)));
  686.                 
  687.             }
  688.         }
  689.     } else {                                                /* it's a subscriber */
  690.         
  691.         HLock((*shortName)->subs);                          /* lock down my list of section handles */
  692.         tempPtr = (SectionHandle *)*(*shortName)->subs;
  693.         for (qq = 0; qq < (*shortName)->numSubs; qq++) {
  694.             
  695.             HLock((Handle)*tempPtr);
  696.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  697.                 SectionHandle removeSection;
  698.                 Handle *tempRectHand;
  699.                 Handle *tempPicHand;
  700.                 Handle *tempPicHand2;
  701.                 removeSection = (*tempPtr);
  702.                 HLock((Handle)removeSection);
  703.                 /* When the user cancels a subscription, you do NOT want to delete the */
  704.                 /* current subscription data (the picture) at this time.  Since the data should be */
  705.                 /* selectable in the document they are working on (text in a text doc, pic in a */
  706.                 /* pic doc, etc) they keep the last subscription data, and delete it */
  707.                 /* seperatly if they'd like */
  708.                 HLock((*shortName)->subRects);
  709.                 HLock((*shortName)->subDataHandle);
  710.                 tempRectHand = (Handle *)*((*shortName)->subRects);
  711.                 tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  712.                 tempRectHand += qq;
  713.                 tempPicHand += qq;
  714.                 
  715.                 /* move the picture over, increase the handle by 1 */
  716.                 (*shortName)->numPicts++;
  717.                 HUnlock((*shortName)->pictHandle);
  718.                 MySetHandleSize((*shortName)->pictHandle, (GetHandleSize((*shortName)->pictHandle) + sizeof(Handle)));
  719.                 HLock((*shortName)->pictHandle);
  720.                 tempPicHand2 = (Handle *)*(*shortName)->pictHandle;
  721.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  722.                 *tempPicHand2 = *tempPicHand;
  723.                 /* move the rect over also */
  724.                 HUnlock((*shortName)->pictRects);
  725.                 MySetHandleSize((*shortName)->pictRects, (GetHandleSize((*shortName)->pictRects) + sizeof(Handle)));
  726.                 HLock((*shortName)->pictRects);
  727.                 tempPicHand2 = (Handle *)*(*shortName)->pictRects;
  728.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  729.                 *tempPicHand2 = *tempRectHand;
  730.                 HUnlock((*shortName)->pictRects);
  731.                 HUnlock((*shortName)->pictHandle);
  732.                 if ((qq + 1) != (*shortName)->numSubs) {
  733.                     register ii;                            /* need to move information down */
  734.                     for (ii = qq; ii < ((*shortName)->numSubs) - 1; ii++) {
  735.                         *tempPtr = *(tempPtr + 1);
  736.                         *tempRectHand = *(tempRectHand + 1);
  737.                         *tempPicHand = *(tempPicHand + 1);
  738.                         tempPtr += 1;
  739.                         tempRectHand += 1;
  740.                         tempPicHand += 1;
  741.                     }
  742.                 }
  743.                 (*shortName)->numSubs--;
  744.                 HUnlock((*shortName)->subs);
  745.                 MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) - sizeof(SectionHandle));
  746.                 HUnlock((*shortName)->subRects);
  747.                 MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) - sizeof(Handle)));
  748.                 
  749.             }
  750.         }
  751.     }
  752.     HUnlock((Handle)shortName);
  753.     /* and clear the highlight */
  754.     if (gShowPub || gShowSub) {
  755.         extern Rect gShowPubRect;
  756.         extern Rect gShowSubRect;
  757.         extern SectionHandle gShowingSecHandle;
  758.         gShowPub = gShowSub = false;
  759.         gShowingSecHandle = nil;
  760.         InvalRect(&gShowPubRect);
  761.         InvalRect(&gShowSubRect);
  762.     }
  763. }
  764.  
  765. /* end MyCancelSection */
  766.  
  767. void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn)
  768. {
  769.     OSErr myErr;
  770.     SectionHandle *tempPtr;
  771.     Handle *tempPicHand;
  772.     Size dataSize;
  773.     EditionRefNum sRefNum;
  774.     /* first we need to determine if this is a PICT or TEXT subscription, since I'm handling */
  775.     /* them differently for drill. */
  776.     myErr = OpenEdition(secHandle, &sRefNum);
  777.     if (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize))
  778.         (*secHandle)->refCon |= kTextType;
  779.     else
  780.         (*secHandle)->refCon |= kPictType;
  781.     /* Now that little mechanism could screw up, if the formats of the section have been */
  782.     /* changed since the subscription was originally created.  But it'll work here */
  783.     CloseEdition(sRefNum, true);
  784.     
  785.     /* increase our section handle holding handle by the size of a handle */
  786.     if (((*secHandle)->refCon & 0xf) == kPictType) {
  787.         HUnlock((*shortName)->subs);
  788.         MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) + sizeof(SectionHandle));
  789.         HLock((*shortName)->subs);
  790.         /* dereference the handle to our section handles in our window structure */
  791.         /* and cast it to a pointer to section handles, since that's what it contains */
  792.         tempPtr = (SectionHandle *)((*(*shortName)->subs) + (sizeof(SectionHandle) * ((*shortName)->numSubs)));
  793.         /* and store our subscriber section */
  794.         *tempPtr = (SectionHandle)secHandle;
  795.         HUnlock((*shortName)->subs);                        /* let it float again */
  796.         /* Here I'm setting up a handle for the picture data contained in the edition we just */
  797.         /* subscribed to, in an array of handles held in the handle subDataHandle  */
  798.         HUnlock((*shortName)->subDataHandle);
  799.         MySetHandleSize((*shortName)->subDataHandle, GetHandleSize((*shortName)->subDataHandle) + sizeof(Handle));  /* allocate */
  800.         HLock((*shortName)->subDataHandle);
  801.         /* deref it */
  802.         tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  803.         tempPicHand += ((*shortName)->numSubs);
  804.         
  805.         if (pictIn == nil)
  806.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  807.         else
  808.             *tempPicHand = pictIn;
  809.         /* ••• NOTE:  You do _NOT_ read the data contained in this section yet! */
  810.         /* All you have done is subscribed to it, the Edition Manager has not told you */
  811.         /* that you can read it!  Wait for the section read event (see below) to get the */
  812.         /* data.  SO I store an empty handle here as a placeholder */
  813.         MoveHHi(*tempPicHand);
  814.         HUnlock((*shortName)->subRects);
  815.         MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) + sizeof(Handle)));  /* allocate a new re*/
  816.         myErr = MemError();
  817.         if (myErr)
  818.             ShowMe("\pMemory error ", myErr, __LINE__);
  819.         HLock((*shortName)->subRects);
  820.         /* generate an empty display rectangle handle also */
  821.         tempPicHand = (Handle *)*((*shortName)->subRects);
  822.         tempPicHand += ((*shortName)->numSubs);
  823.         
  824.         if (inRect == nil)
  825.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  826.         else
  827.             *tempPicHand = inRect;
  828.         MoveHHi(*tempPicHand);
  829.         (*shortName)->numSubs++;                            /* increment our count of subscribers */
  830.         HUnlock((*shortName)->subRects);
  831.         HUnlock((*shortName)->subDataHandle);
  832.     } else {
  833.         if (((*secHandle)->refCon & 0xf) == kTextType) {        /* double checking here */
  834.             mySectionDataHandle newSection;
  835.             /* get a new text section record */
  836.             if (inRect == nil) {
  837.                 /* this means that it is being created fresh, so we have to get a */
  838.                 /* text section record from my routine */
  839.                 newSection = GetTextSection(shortName, stSubscriber);
  840.                 /* fill it with stuff relating to the section we just created */
  841.                 (*newSection)->publishing = false;
  842.                 (*newSection)->theID = (*secHandle)->sectionID;
  843.                 (*newSection)->theSection = secHandle;
  844.             } else {
  845.                 newSection = (mySectionDataHandle)inRect;
  846.             }
  847.             /* store it in our window structure */
  848.             if ((*shortName)->textSections) {
  849.                 mySectionDataHandle tempSection = (*shortName)->textSections;
  850.                 if ((*shortName)->textSections) {
  851.                     while ((*tempSection)->nextSection)
  852.                         tempSection = (*tempSection)->nextSection;
  853.                 }
  854.                 (*tempSection)->nextSection = newSection;
  855.                 
  856.             } else {
  857.                 /* first one */
  858.                 (*shortName)->textSections = newSection;
  859.             }
  860.         }
  861.     }
  862. }
  863.  
  864. pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr)
  865. {
  866. #pragma unused (yourDataPtr)
  867.     short myHit;
  868.     short itemType;
  869.     ControlHandle theButton;
  870.     Rect theRect;
  871.     /* first make sure that a sub-dialog is not frontmost */
  872.     /* so we don't filter keys or hits to a sub-dialog */
  873.     if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) {
  874.         /* first see if it's the 'first call' item (see the Standard File chapter).  If it is, then */
  875.         /* we preset our check box */
  876.         if (itemHit == -1) {
  877.             /* this gets the handle to our check box, since we know it's one past the last standard item */
  878.             GetDItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  879.             SetCtlValue(theButton, gResizeSub);             /* and set our current value */
  880.         } else {
  881.             /* only have one item in this expansion, but we'll check the range anyway to be safe */
  882.             myHit = itemHit - itemOffset;                   /* since our item numbers are relative to the total number */
  883.             /* of items in the dialog, and the system may change.  Always do your item numbering based */
  884.             /* on the offset, this will prevent incompatability when the system dialog grows or shrinks */
  885.             if (myHit == 1) {                               /* I only added one item, so this be the one */
  886.                 /* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */
  887.                 /* additive dialog.  It is counting from the actual start of the DITL, not the start of */
  888.                 /* your custom items */
  889.                 GetDItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect);
  890.                 if (GetCtlValue(theButton))
  891.                     gResizeSub = false;
  892.                 else
  893.                     gResizeSub = true;
  894.                 SetCtlValue(theButton, gResizeSub);
  895.             }
  896.         }
  897.     }
  898.     return(itemHit);                                        /* the return value must be absolute */
  899. }
  900.  
  901. pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr)
  902. {
  903. #pragma unused (itemHit,yourDataPtr) 
  904.     short itemType;
  905.     ControlHandle theButton;
  906.     Rect theRect;
  907.     /* first make sure that a sub-dialog is not frontmost */
  908.     /* so we don't filter keys or hits to a sub-dialog */
  909.     if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) {
  910.         /* standard filter proc kinda stuff here */
  911.         if ((theEvent->what) == keyDown) {
  912.             char tempChar;
  913.             tempChar = theEvent->message & charCodeMask;
  914.             
  915.             if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) {
  916.                 /* they pressed an A with the command key down, we get to handle it. */
  917.                 GetDItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  918.                 if (GetCtlValue(theButton))
  919.                     gResizeSub = false;
  920.                 else
  921.                     gResizeSub = true;
  922.                 SetCtlValue(theButton, gResizeSub);
  923.                 return(true);                               /* tell folks we handled it */
  924.             }
  925.         }
  926.     }
  927.     return(false);                                          /* was not a keystroke we wanted */
  928.     
  929. }
  930.  
  931. /* DeleteSubscriber is called by a menu command 'Clear' */
  932.  
  933. void DeleteSubscriber(void)
  934. {
  935.     if (StopAlert(kCanxSub, (ModalFilterProcPtr)standardAlertFilter) == 2) {
  936.         MyCancelSection(gShowingSecHandle, FindSection(gShowingSecHandle));
  937.         
  938.     }
  939. }
  940.  
  941. /* end DeleteSubscriber */
  942.  
  943. /* PasteSubscription pastes the section (a subscriber) from the clipboard into the */
  944. /* frontmost window (as you would expect) */
  945. void PasteSubscription(void)
  946. {
  947.     
  948.     windowCHandle tempWC;
  949.     SectionHandle tempHandle;
  950.     AliasHandle tempHandle2;
  951.     FSSpec newFileSpec;
  952.     Boolean myWasChanged;
  953.     Rect tempPRect =  {
  954.         0, 0, 40, 40
  955.     };
  956.     long myOffset;
  957.     long fred;
  958.     Handle tempRectHand = NewHandle(sizeof(Rect));
  959.     /* first see if there is a section handle on the clipboard */
  960.     /* kill the current section on the clipboard, if there is one */
  961.     /* •••• NEW, we're looking for section handles and aliases on the clipboard.  */
  962.     
  963.     /* set up a dummy picture for this incoming section.... */
  964.     if (!gScrapData)
  965.         gScrapData = NewHandle(0);
  966.     fred = GetScrap(gScrapData, rSectionType, &myOffset);
  967.     if (fred > 0) {                                         /* if there is a section on the clipboard */
  968.         myOffset = 0;
  969.         /* read in the rect also */
  970.         
  971.         fred = GetScrap(tempRectHand, kRECTType, &myOffset);
  972.         
  973.         if (fred > 0) {
  974.             short offH, offV;
  975.             /* move the rect to the upper left */
  976.             offH = (*(Rect *)*tempRectHand).right - (*(Rect *)*tempRectHand).left;
  977.             offV = (*(Rect *)*tempRectHand).bottom - (*(Rect *)*tempRectHand).top;
  978.             (*(Rect *)*tempRectHand).left = 0;
  979.             (*(Rect *)*tempRectHand).top = 0;
  980.             (*(Rect *)*tempRectHand).right = offH;
  981.             (*(Rect *)*tempRectHand).bottom = offV;
  982.             /* and read in the pict */
  983.             myOffset = 0;
  984.             GetScrap((Handle)gClipPict, kGenericPICTWord, &myOffset);
  985.         } else {
  986.             *(Rect *)*tempRectHand = tempPRect;             /* default it */
  987.         }
  988.     }
  989.     HLock(tempRectHand);
  990.     tempWC = (windowCHandle)GetWRefCon(FrontWindow());
  991.     HLock((Handle)tempWC);
  992.     if (gClipPict && GetHandleSize((Handle)gClipPict)) {
  993.         InvalRect((Rect *)*tempRectHand);
  994.         
  995.     } else {
  996.         *(Rect *)(*tempRectHand) = tempPRect;
  997.     }
  998.     /* update the ID of the section to include the master ID of the window yer pasting into */
  999.     (*gClipSection)->sectionID += (*tempWC)->windowID;
  1000.     StoreSubscriber(tempWC, gClipSection, tempRectHand, (Handle)gClipPict);
  1001.     HUnlock((Handle)tempWC);
  1002.     /* Now, after you paste the subscription, you have to change the subscription on the clipboard. */
  1003.     /* You need to duplicate it, and assign a new ID number, since if the thing is pasted again */
  1004.     /* you could have two subscriptions with the same ID, which would not be nice.  So we do this... */
  1005.     tempHandle = gClipSection;
  1006.     tempHandle2 = (*gClipSection)->alias;
  1007.     HandToHand((Handle *)&tempHandle);
  1008.     HandToHand((Handle *)&tempHandle2);
  1009.     (*tempHandle)->sectionID = gSectionID;
  1010.     (*tempHandle)->alias = tempHandle2;
  1011.     gSectionID++;
  1012.     /* now register the section so the edition manager knows to send you updates */
  1013.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1014.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1015.         gClipSection = tempHandle;
  1016.     gClipHasContents = kClipHasSub;
  1017.     MyReadSection(tempHandle);
  1018.     
  1019. }
  1020. /* CutSubscription and CopySubscription move the current selection in the active window to the */
  1021. /* ClipBoard.  The main difference here from standard scrap handling is that the scrap you now */
  1022. /* have is dynamic.  The contents of the clipboard can change if the publisher of this subscription */
  1023. /* changes, so you must treat this section as you would any other subscriber */
  1024. /* frontmost window (as you would expect) */
  1025. void CutSubscription(void)
  1026. {
  1027.     CopySubscription();
  1028.     DeleteSubscriber();                                     /* even though they said cut, I want to make sure that they really mean it */
  1029. }
  1030. /* CopySubscriber moves the current display subscriber to the clipboard, making a new */
  1031. /* subscription in the process, since we don't want to have two copies of the same thing */
  1032. void CopySubscription(void)
  1033. {
  1034.     SectionHandle tempHandle;
  1035.     AliasHandle tempHandle2;
  1036.     FSSpec newFileSpec;
  1037.     Boolean myWasChanged;
  1038.     /* First check to see if there is already a section to remove */
  1039.     if (gClipHasContents == kClipHasSub) {
  1040.         KillClipSub();
  1041.     }
  1042.     tempHandle = gShowingSecHandle;
  1043.     /* copy the alias also */
  1044.     tempHandle2 = (*gShowingSecHandle)->alias;
  1045.     HandToHand((Handle *)&tempHandle);
  1046.     HandToHand((Handle *)&tempHandle2);
  1047.     /* create a unique ID for this section.  I'll just use the next section ID */
  1048.     (*tempHandle)->sectionID = gSectionID;
  1049.     (*tempHandle)->alias = tempHandle2;
  1050.     gSectionID++;
  1051.     /* now register the section so the edition manager knows to send you updates */
  1052.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1053.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1054.         gClipSection = tempHandle;
  1055.     gClipPict = (PicHandle)NewHandle(0);                    /* allocate an empty handle for this picture data */
  1056.     gClipHasContents = kClipHasSub;
  1057.     /* write the section handle out to the cipboard */
  1058.     ZeroScrap();
  1059.     PutScrap(sizeof(Handle), rSectionType, (Ptr)&tempHandle);
  1060.     PutScrap(sizeof(Rect), kRECTType, (Ptr)&gShowSubRect);
  1061.     
  1062.     MyReadSection(tempHandle);
  1063.     
  1064.     InitCursor();                                           /* set to watch by MyReadSection, would normally be reset next pass */
  1065.     /* through the event loop, but NOT if it's being called by Cut, */
  1066.     /* so I'll reset it just to be safe */
  1067. }
  1068.  
  1069. OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum)
  1070. {OSErr myErr = noErr;
  1071.     extern Handle gScrapData;
  1072.     MySetHandleSize((Handle)gClipPict, readIn);
  1073.     HLock((Handle)gClipPict);
  1074.     /* read the pict in */
  1075.     myErr = MyReadEditionData((Ptr)*gClipPict, kGenericPICTWord, sRefNum, &readIn);
  1076.     HUnlock((Handle)gClipPict);
  1077.     gScrapData = (Handle)gClipPict;
  1078.     if (((WindowPeek)FindClipWindow())->visible) {
  1079.         WindowPtr temp;
  1080.         GetPort(&temp);
  1081.         SetPort(FindClipWindow());
  1082.         InvalRect(&FindClipWindow()->portRect);
  1083.         SetPort(temp);
  1084.     }    
  1085. return(myErr);
  1086. }
  1087. /* This kills the current section on the clipboard, since it's being replaced */
  1088. /* and you don't want to receive events for it anymore */
  1089. void KillClipSub(void)
  1090. {
  1091.     UnRegisterSection(gClipSection);
  1092.     DisposHandle((Handle)(*gClipSection)->alias);
  1093.     DisposeHandle((Handle)gClipSection);
  1094.     gClipSection = nil;
  1095.     gClipHasContents = kClipEmpty;
  1096.     if (GetHandleSize((Handle)gClipPict) != nil)
  1097.         KillPicture(gClipPict);
  1098. }
  1099.  
  1100. /* MyGoToPublisher is used if the user was holding down the Option key during a */
  1101. /* double click, to send them to the publisher without seeing the dialog box */
  1102. OSErr MyGoToPublisher(SectionHandle theSection)
  1103. {
  1104.     EditionInfoRecord theEdInfo;
  1105.     
  1106.     GetEditionInfo(theSection, &theEdInfo);
  1107.     return(GoToPublisherSection(&theEdInfo.container));
  1108. }
  1109.  
  1110. /* Searches the subcriber list, hilites the selection, and drags it */
  1111. /* This is very similar to the publisher check, but has added functionality */
  1112. /* for dragging the subscriber around the window */
  1113. Boolean SearchSubs(Point thePoint)
  1114. {
  1115.     register qq;
  1116.     Str63 pubString;
  1117.     Handle *theRectsHandle;
  1118.     Boolean subGotIt = false;
  1119.     windowCHandle shortname = (windowCHandle)GetWRefCon(FrontWindow());
  1120.     HLock((Handle)shortname);
  1121.     if ((*shortname)->numSubs) {                            /* does it have any subscribers? */
  1122.         HLock((*shortname)->subRects);                      /* lock down the rect handle */
  1123.         /* cast it as a pointer to handles for reading ease */
  1124.         theRectsHandle = (Handle *)*(*shortname)->subRects;
  1125.         for (qq = 0; qq < (*shortname)->numSubs; qq++) {        /* step through the subscribers */
  1126.             SectionHandle *tempPtr;
  1127.             Rect *checkRect;
  1128.             Rect cornerRect;
  1129.             HLock(*theRectsHandle);
  1130.             checkRect = (Rect *)**theRectsHandle;
  1131.             /* did they click in this rect? */
  1132.             InsetRect(checkRect, kNegFour, kNegFour);                   /* include the possible borders */
  1133.             if (PtInRect(thePoint, checkRect)) {            /* yes */
  1134.                 /* erase the old display rectangles, if there are any */
  1135.                 if (gShowSub){
  1136.                     InsetRect(&gShowSubRect, kNegFour, kNegFour);
  1137.                     InvalRect(&gShowSubRect);
  1138.                     InsetRect(&gShowSubRect, kFour, kFour);
  1139.  
  1140.                     }
  1141.                 gShowSub = true;
  1142.                 if (gShowPub) {
  1143.                     InvalRect(&gShowPubRect);
  1144.                     gShowPub = false;
  1145.                 }
  1146.                 /* get the section handle for this section */
  1147.                 HLock((*shortname)->subs);
  1148.                 tempPtr = (SectionHandle *)*(*shortname)->subs;
  1149.                 tempPtr += qq;
  1150.                 gShowingSecHandle = *tempPtr;
  1151.                 HUnlock((*shortname)->subs);
  1152.                 /* change the menu item name now */
  1153.                 GetIndString(pubString, kGeneralStrings, kSubOptString);
  1154.                 
  1155.                 SetItem(gEditMenuHandle, kSoptionsItem,pubString);
  1156.                 
  1157.                 InvalRect(checkRect);                       /* make sure it gets redrawn */
  1158.                 /* now I want the actual rect values so I can drag it around */
  1159.                 /* in response to the user */
  1160.                 gShowSubRect = *checkRect;
  1161.                 PenPat(&qd.dkGray);
  1162.                 PenSize(3, 3);
  1163.                 FrameRect(&gShowSubRect);
  1164.                 PenSize(1, 1);
  1165.                 /* Here you drag the thing around to where the user wants it, updating the 
  1166.                 *   window record as you do it. */
  1167.                 GetMouse(&thePoint);
  1168.                 InvalRect(&gShowSubRect);
  1169.                 /* two choices here.  They could be dragging the whole thing, or resizing it.  */
  1170.                 /* The resize box is in the lower right ten pixels, I'll say, so if the original */
  1171.                 /* click is there I'll go to the resize routine */
  1172.                 cornerRect = gShowSubRect;
  1173.                 cornerRect.top = cornerRect.bottom - 7;
  1174.                 cornerRect.left = cornerRect.right - 7;
  1175.                 if (PtInRect(thePoint, &cornerRect) && gResizeSub) {
  1176.                     
  1177.                     PullRect(shortname, &gShowSubRect, false, true,true);
  1178.                     
  1179.                 } else {
  1180.                     while (StillDown()) {                   /* keep doing it until they release the mouse */
  1181.                         Point tempPoint;
  1182.                          PenMode(patXor);
  1183.                          FrameRect(&gShowSubRect);           /* nasty way to put up a flashing border for the drag */
  1184.                          FrameRect(&gShowSubRect);
  1185.                         GetMouse(&tempPoint);
  1186.                         /* keep inside the window please, don't let them drag the */
  1187.                         /* rectangle outside the window bounds */
  1188.                         if (PtInRect(tempPoint, &(FrontWindow()->portRect))) {
  1189.                             if (tempPoint != thePoint) {
  1190.                                 OffsetRect(&gShowSubRect, tempPoint.h - thePoint.h, tempPoint.v - thePoint.v);
  1191.                                 thePoint = tempPoint;
  1192.                             }
  1193.                         }
  1194.                     }
  1195.                     PenMode(normal);
  1196.                 }
  1197.                 InvalRect(&gShowSubRect);
  1198.                 InsetRect(checkRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
  1199.                 InsetRect(&gShowSubRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
  1200.  
  1201.                 if (gShowSubRect != *checkRect) {           /* don't update if they didn't end up moving it */
  1202.  
  1203.  
  1204.                         *checkRect = gShowSubRect;          /* update our record of things */
  1205.                 }
  1206.  
  1207.                 
  1208.                 
  1209.                 subGotIt = true;
  1210.             } else {
  1211.             /* shrink it back agin */
  1212.             InsetRect(checkRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
  1213.  
  1214.             }
  1215.             HUnlock(*theRectsHandle);
  1216.             theRectsHandle += 1;                            /* increase by one Rect to check next */
  1217.             if (subGotIt)
  1218.                 break;
  1219.         }
  1220.         HUnlock((*shortname)->subRects);
  1221.     }
  1222.     HUnlock((Handle)shortname);
  1223.     return(subGotIt);
  1224. }
  1225.  
  1226. /* end SearchSubs */
  1227.  
  1228.  
  1229.  
  1230.  
  1231. #undef __SUBSCRIBE__
  1232.